package cn.jbolt.core.captcha;

import cn.jbolt.core.consts.JBoltConst;
import cn.jbolt.core.kit.JBoltControllerKit;
import com.jfinal.captcha.Captcha;
import com.jfinal.captcha.CaptchaManager;
import com.jfinal.captcha.CaptchaRender;
import com.jfinal.core.JFinal;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.render.RenderException;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class JBoltCaptchaRender extends CaptchaRender {
	protected String type = JBoltConst.JBOLT_CAPTCHA_TYPE_DEFAULT;
	public static final String CAPTCHA_KEY = "jbcapkey";
	protected static final String CONTENT_TYPE_IMG_GIF = "image/gif";
	protected static final String CONTENT_TYPE_IMG_PNG = "image/png";
	protected static final String CONTENT_TYPE_IMG_JPEG = "image/jpeg";

	public JBoltCaptchaRender() {
		super();
	}

	public JBoltCaptchaRender(String type) {
		this.type = type;
	}

	/**
	 * 生成验证码
	 */
	@Override
	public void render() {
		if (type == null) {
			superRender();
			return;
		}
		switch (type) {
		case JBoltConst.JBOLT_CAPTCHA_TYPE_DEFAULT:
			superRender();
			break;
		case JBoltConst.JBOLT_CAPTCHA_TYPE_GIF:
			renderGifCaptcha();
			break;
		case JBoltConst.JBOLT_CAPTCHA_TYPE_BUBBLE_PNG:
			renderBubblePngCaptcha();
			break;
		case JBoltConst.JBOLT_CAPTCHA_TYPE_NUMBER_CALC:
			renderNumberCalcPngCaptcha(false);
			break;
		case JBoltConst.JBOLT_CAPTCHA_TYPE_NUMBER_CALC_CN:
			renderNumberCalcPngCaptcha(true);
			break;
		default:
			superRender();
			break;
		}

	}

	private void superRender() {
		Captcha captcha = createCaptcha();
		CaptchaManager.me().getCaptchaCache().put(captcha);

		Cookie cookie = new Cookie(captchaName, captcha.getKey());
		cookie.setMaxAge(-1);
		String path = JFinal.me().getContextPath();
		if (StrKit.isBlank(path)) {
			path = "/";
		}
		cookie.setPath(path);
		response.addCookie(cookie);
		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		response.setContentType(CONTENT_TYPE_IMG_JPEG);
		response.setHeader(CAPTCHA_KEY,captcha.getKey());

		ServletOutputStream sos = null;
		try {
			BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
			drawGraphic(captcha.getValue(), image);

			sos = response.getOutputStream();
			ImageIO.write(image, "jpeg", sos);
		} catch (IOException e) {
			if (getDevMode()) {
				throw new RenderException(e);
			}
		} catch (Exception e) {
			throw new RenderException(e);
		} finally {
			if (sos != null) {
				try {
					sos.close();
				} catch (IOException e) {
					LogKit.logNothing(e);
				}
			}
		}
	}

	/**
	 * 生成gif 验证码
	 */
	private void renderGifCaptcha() {
		JBoltCaptcha captcha = new JBoltGifCaptcha(108, 40, 4);
		genCaptcha(captcha);
	}

	/**
	 * 生成气泡PNG验证码
	 */
	private void renderBubblePngCaptcha() {
		JBoltCaptcha captcha = new JBoltSpecCaptcha(108, 40, 4);
		genCaptcha(captcha);
	}

	/**
	 * 生成数字运算验证码
	 *
	 * @param iscn 是否中文
	 */
	private void renderNumberCalcPngCaptcha(boolean iscn) {
		String captchaKey = getCaptchaKeyFromCookie();
		if (StrKit.isBlank(captchaKey)) {
			captchaKey = StrKit.getRandomUUID();
		}
		BufferedImage image = null;
		String resultString = null;
		if (iscn) {
			NumberCalcCnCaptcha np = new NumberCalcCnCaptcha();
			image = np.drawVerificationCodeImage();
			resultString = np.getCalcResultStr();
		} else {
			NumberCalcCaptcha nc = new NumberCalcCaptcha();
			image = nc.create();
			resultString = nc.resultStr();
		}
		Captcha captcha = new Captcha(captchaKey, resultString, Captcha.DEFAULT_EXPIRE_TIME);
		CaptchaManager.me().getCaptchaCache().put(captcha);

		Cookie cookie = new Cookie(captchaName, captcha.getKey());
		cookie.setMaxAge(-1);
		String path = JFinal.me().getContextPath();
		if (StrKit.isBlank(path)) {
			path = "/";
		}
		cookie.setPath(path);
		response.addCookie(cookie);
		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		response.setContentType(CONTENT_TYPE_IMG_PNG);
		response.setHeader(CAPTCHA_KEY,captcha.getKey());

		ServletOutputStream sos = null;
		try {
			sos = response.getOutputStream();
			ImageIO.write(image, "png", sos);
		} catch (IOException e) {
			if (getDevMode()) {
				throw new RenderException(e);
			}
		} catch (Exception e) {
			throw new RenderException(e);
		} finally {
			if (sos != null) {
				try {
					sos.close();
				} catch (IOException e) {
					LogKit.logNothing(e);
				}
			}
		}
	}

	protected String genKey() {
		String captchaKey = getCaptchaKeyFromCookie();
		if (StrKit.isBlank(captchaKey)) {
			captchaKey = StrKit.getRandomUUID();
		}
		return captchaKey;
	}

	/**
	 * 底层生成方法
	 * @param captcha
	 */
	private void genCaptcha(JBoltCaptcha captcha) {
		captcha.gen(genKey());
		CaptchaManager.me().getCaptchaCache().put(captcha);
		try {
			Cookie cookie = new Cookie(captchaName, captcha.getKey());
			cookie.setMaxAge(-1);
			String path = JFinal.me().getContextPath();
			if (StrKit.isBlank(path)) {
				path = "/";
			}
			cookie.setPath(path);
			response.addCookie(cookie);
			response.setHeader("Pragma", "No-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setDateHeader("Expires", 0);
			response.setHeader(CAPTCHA_KEY,captcha.getKey());
			switch (type) {
			case JBoltConst.JBOLT_CAPTCHA_TYPE_GIF:
				response.setContentType(CONTENT_TYPE_IMG_GIF);
				break;
			case JBoltConst.JBOLT_CAPTCHA_TYPE_BUBBLE_PNG:
				response.setContentType(CONTENT_TYPE_IMG_PNG);
				break;
			}

			// 输出
			captcha.out(response.getOutputStream());

		} catch (Exception e) {
			Log.getLog(JBoltControllerKit.class).error("获取验证码异常：" + e.getMessage());
		}
	}

}
